home *** CD-ROM | disk | FTP | other *** search
/ Clickx 96 / Clickx 96.iso / software / tools / tool / xbmc-10.1.exe / system / python / Lib / bsddb / __init__.py next >
Encoding:
Text File  |  2011-03-08  |  12.8 KB  |  390 lines

  1. #----------------------------------------------------------------------
  2. #  Copyright (c) 1999-2001, Digital Creations, Fredericksburg, VA, USA
  3. #  and Andrew Kuchling. All rights reserved.
  4. #
  5. #  Redistribution and use in source and binary forms, with or without
  6. #  modification, are permitted provided that the following conditions are
  7. #  met:
  8. #
  9. #    o Redistributions of source code must retain the above copyright
  10. #      notice, this list of conditions, and the disclaimer that follows.
  11. #
  12. #    o Redistributions in binary form must reproduce the above copyright
  13. #      notice, this list of conditions, and the following disclaimer in
  14. #      the documentation and/or other materials provided with the
  15. #      distribution.
  16. #
  17. #    o Neither the name of Digital Creations nor the names of its
  18. #      contributors may be used to endorse or promote products derived
  19. #      from this software without specific prior written permission.
  20. #
  21. #  THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS
  22. #  IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  23. #  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  24. #  PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL
  25. #  CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. #  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. #  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. #  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  29. #  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  30. #  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  31. #  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  32. #  DAMAGE.
  33. #----------------------------------------------------------------------
  34.  
  35.  
  36. """Support for BerkeleyDB 3.2 through 4.2.
  37. """
  38.  
  39. try:
  40.     if __name__ == 'bsddb3':
  41.         # import _pybsddb binary as it should be the more recent version from
  42.         # a standalone pybsddb addon package than the version included with
  43.         # python as bsddb._bsddb.
  44.         import _pybsddb
  45.         _bsddb = _pybsddb
  46.     else:
  47.         import _bsddb
  48. except ImportError:
  49.     # Remove ourselves from sys.modules
  50.     import sys
  51.     del sys.modules[__name__]
  52.     raise
  53.  
  54. # bsddb3 calls it db, but provide _db for backwards compatibility
  55. db = _db = _bsddb
  56. __version__ = db.__version__
  57.  
  58. error = db.DBError  # So bsddb.error will mean something...
  59.  
  60. #----------------------------------------------------------------------
  61.  
  62. import sys, os
  63.  
  64. # for backwards compatibility with python versions older than 2.3, the
  65. # iterator interface is dynamically defined and added using a mixin
  66. # class.  old python can't tokenize it due to the yield keyword.
  67. if sys.version >= '2.3':
  68.     import UserDict
  69.     from weakref import ref
  70.     exec """
  71. class _iter_mixin(UserDict.DictMixin):
  72.     def _make_iter_cursor(self):
  73.         cur = self.db.cursor()
  74.         key = id(cur)
  75.         self._cursor_refs[key] = ref(cur, self._gen_cref_cleaner(key))
  76.         return cur
  77.  
  78.     def _gen_cref_cleaner(self, key):
  79.         # use generate the function for the weakref callback here
  80.         # to ensure that we do not hold a strict reference to cur
  81.         # in the callback.
  82.         return lambda ref: self._cursor_refs.pop(key, None)
  83.  
  84.     def __iter__(self):
  85.         try:
  86.             cur = self._make_iter_cursor()
  87.  
  88.             # FIXME-20031102-greg: race condition.  cursor could
  89.             # be closed by another thread before this call.
  90.  
  91.             # since we're only returning keys, we call the cursor
  92.             # methods with flags=0, dlen=0, dofs=0
  93.             key = cur.first(0,0,0)[0]
  94.             yield key
  95.  
  96.             next = cur.next
  97.             while 1:
  98.                 try:
  99.                     key = next(0,0,0)[0]
  100.                     yield key
  101.                 except _bsddb.DBCursorClosedError:
  102.                     cur = self._make_iter_cursor()
  103.                     # FIXME-20031101-greg: race condition.  cursor could
  104.                     # be closed by another thread before this call.
  105.                     cur.set(key,0,0,0)
  106.                     next = cur.next
  107.         except _bsddb.DBNotFoundError:
  108.             return
  109.         except _bsddb.DBCursorClosedError:
  110.             # the database was modified during iteration.  abort.
  111.             return
  112.  
  113.     def iteritems(self):
  114.         try:
  115.             try:
  116.                 cur = self._make_iter_cursor()
  117.             except AttributeError:
  118.                 return
  119.  
  120.             # FIXME-20031102-greg: race condition.  cursor could
  121.             # be closed by another thread before this call.
  122.  
  123.             kv = cur.first()
  124.             key = kv[0]
  125.             yield kv
  126.  
  127.             next = cur.next
  128.             while 1:
  129.                 try:
  130.                     kv = next()
  131.                     key = kv[0]
  132.                     yield kv
  133.                 except _bsddb.DBCursorClosedError:
  134.                     cur = self._make_iter_cursor()
  135.                     # FIXME-20031101-greg: race condition.  cursor could
  136.                     # be closed by another thread before this call.
  137.                     cur.set(key,0,0,0)
  138.                     next = cur.next
  139.         except _bsddb.DBNotFoundError:
  140.             return
  141.         except _bsddb.DBCursorClosedError:
  142.             # the database was modified during iteration.  abort.
  143.             return
  144. """
  145. else:
  146.     class _iter_mixin: pass
  147.  
  148.  
  149. class _DBWithCursor(_iter_mixin):
  150.     """
  151.     A simple wrapper around DB that makes it look like the bsddbobject in
  152.     the old module.  It uses a cursor as needed to provide DB traversal.
  153.     """
  154.     def __init__(self, db):
  155.         self.db = db
  156.         self.db.set_get_returns_none(0)
  157.  
  158.         # FIXME-20031101-greg: I believe there is still the potential
  159.         # for deadlocks in a multithreaded environment if someone
  160.         # attempts to use the any of the cursor interfaces in one
  161.         # thread while doing a put or delete in another thread.  The
  162.         # reason is that _checkCursor and _closeCursors are not atomic
  163.         # operations.  Doing our own locking around self.dbc,
  164.         # self.saved_dbc_key and self._cursor_refs could prevent this.
  165.         # TODO: A test case demonstrating the problem needs to be written.
  166.  
  167.         # self.dbc is a DBCursor object used to implement the
  168.         # first/next/previous/last/set_location methods.
  169.         self.dbc = None
  170.         self.saved_dbc_key = None
  171.  
  172.         # a collection of all DBCursor objects currently allocated
  173.         # by the _iter_mixin interface.
  174.         self._cursor_refs = {}
  175.  
  176.     def __del__(self):
  177.         self.close()
  178.  
  179.     def _checkCursor(self):
  180.         if self.dbc is None:
  181.             self.dbc = self.db.cursor()
  182.             if self.saved_dbc_key is not None:
  183.                 self.dbc.set(self.saved_dbc_key)
  184.                 self.saved_dbc_key = None
  185.  
  186.     # This method is needed for all non-cursor DB calls to avoid
  187.     # BerkeleyDB deadlocks (due to being opened with DB_INIT_LOCK
  188.     # and DB_THREAD to be thread safe) when intermixing database
  189.     # operations that use the cursor internally with those that don't.
  190.     def _closeCursors(self, save=1):
  191.         if self.dbc:
  192.             c = self.dbc
  193.             self.dbc = None
  194.             if save:
  195.                 try:
  196.                     self.saved_dbc_key = c.current(0,0,0)[0]
  197.                 except db.DBError:
  198.                     pass
  199.             c.close()
  200.             del c
  201.         for cref in self._cursor_refs.values():
  202.             c = cref()
  203.             if c is not None:
  204.                 c.close()
  205.  
  206.     def _checkOpen(self):
  207.         if self.db is None:
  208.             raise error, "BSDDB object has already been closed"
  209.  
  210.     def isOpen(self):
  211.         return self.db is not None
  212.  
  213.     def __len__(self):
  214.         self._checkOpen()
  215.         return len(self.db)
  216.  
  217.     def __getitem__(self, key):
  218.         self._checkOpen()
  219.         return self.db[key]
  220.  
  221.     def __setitem__(self, key, value):
  222.         self._checkOpen()
  223.         self._closeCursors()
  224.         self.db[key] = value
  225.  
  226.     def __delitem__(self, key):
  227.         self._checkOpen()
  228.         self._closeCursors()
  229.         del self.db[key]
  230.  
  231.     def close(self):
  232.         self._closeCursors(save=0)
  233.         if self.dbc is not None:
  234.             self.dbc.close()
  235.         v = 0
  236.         if self.db is not None:
  237.             v = self.db.close()
  238.         self.dbc = None
  239.         self.db = None
  240.         return v
  241.  
  242.     def keys(self):
  243.         self._checkOpen()
  244.         return self.db.keys()
  245.  
  246.     def has_key(self, key):
  247.         self._checkOpen()
  248.         return self.db.has_key(key)
  249.  
  250.     def set_location(self, key):
  251.         self._checkOpen()
  252.         self._checkCursor()
  253.         return self.dbc.set_range(key)
  254.  
  255.     def next(self):
  256.         self._checkOpen()
  257.         self._checkCursor()
  258.         rv = self.dbc.next()
  259.         return rv
  260.  
  261.     def previous(self):
  262.         self._checkOpen()
  263.         self._checkCursor()
  264.         rv = self.dbc.prev()
  265.         return rv
  266.  
  267.     def first(self):
  268.         self._checkOpen()
  269.         self._checkCursor()
  270.         rv = self.dbc.first()
  271.         return rv
  272.  
  273.     def last(self):
  274.         self._checkOpen()
  275.         self._checkCursor()
  276.         rv = self.dbc.last()
  277.         return rv
  278.  
  279.     def sync(self):
  280.         self._checkOpen()
  281.         return self.db.sync()
  282.  
  283.  
  284. #----------------------------------------------------------------------
  285. # Compatibility object factory functions
  286.  
  287. def hashopen(file, flag='c', mode=0666, pgsize=None, ffactor=None, nelem=None,
  288.             cachesize=None, lorder=None, hflags=0):
  289.  
  290.     flags = _checkflag(flag, file)
  291.     e = _openDBEnv(cachesize)
  292.     d = db.DB(e)
  293.     d.set_flags(hflags)
  294.     if pgsize is not None:    d.set_pagesize(pgsize)
  295.     if lorder is not None:    d.set_lorder(lorder)
  296.     if ffactor is not None:   d.set_h_ffactor(ffactor)
  297.     if nelem is not None:     d.set_h_nelem(nelem)
  298.     d.open(file, db.DB_HASH, flags, mode)
  299.     return _DBWithCursor(d)
  300.  
  301. #----------------------------------------------------------------------
  302.  
  303. def btopen(file, flag='c', mode=0666,
  304.             btflags=0, cachesize=None, maxkeypage=None, minkeypage=None,
  305.             pgsize=None, lorder=None):
  306.  
  307.     flags = _checkflag(flag, file)
  308.     e = _openDBEnv(cachesize)
  309.     d = db.DB(e)
  310.     if pgsize is not None: d.set_pagesize(pgsize)
  311.     if lorder is not None: d.set_lorder(lorder)
  312.     d.set_flags(btflags)
  313.     if minkeypage is not None: d.set_bt_minkey(minkeypage)
  314.     if maxkeypage is not None: d.set_bt_maxkey(maxkeypage)
  315.     d.open(file, db.DB_BTREE, flags, mode)
  316.     return _DBWithCursor(d)
  317.  
  318. #----------------------------------------------------------------------
  319.  
  320.  
  321. def rnopen(file, flag='c', mode=0666,
  322.             rnflags=0, cachesize=None, pgsize=None, lorder=None,
  323.             rlen=None, delim=None, source=None, pad=None):
  324.  
  325.     flags = _checkflag(flag, file)
  326.     e = _openDBEnv(cachesize)
  327.     d = db.DB(e)
  328.     if pgsize is not None: d.set_pagesize(pgsize)
  329.     if lorder is not None: d.set_lorder(lorder)
  330.     d.set_flags(rnflags)
  331.     if delim is not None: d.set_re_delim(delim)
  332.     if rlen is not None: d.set_re_len(rlen)
  333.     if source is not None: d.set_re_source(source)
  334.     if pad is not None: d.set_re_pad(pad)
  335.     d.open(file, db.DB_RECNO, flags, mode)
  336.     return _DBWithCursor(d)
  337.  
  338. #----------------------------------------------------------------------
  339.  
  340. def _openDBEnv(cachesize):
  341.     e = db.DBEnv()
  342.     if cachesize is not None:
  343.         if cachesize >= 20480:
  344.             e.set_cachesize(0, cachesize)
  345.         else:
  346.             raise error, "cachesize must be >= 20480"
  347.     e.open('.', db.DB_PRIVATE | db.DB_CREATE | db.DB_THREAD | db.DB_INIT_LOCK | db.DB_INIT_MPOOL)
  348.     return e
  349.  
  350. def _checkflag(flag, file):
  351.     if flag == 'r':
  352.         flags = db.DB_RDONLY
  353.     elif flag == 'rw':
  354.         flags = 0
  355.     elif flag == 'w':
  356.         flags =  db.DB_CREATE
  357.     elif flag == 'c':
  358.         flags =  db.DB_CREATE
  359.     elif flag == 'n':
  360.         flags = db.DB_CREATE
  361.         #flags = db.DB_CREATE | db.DB_TRUNCATE
  362.         # we used db.DB_TRUNCATE flag for this before but BerkeleyDB
  363.         # 4.2.52 changed to disallowed truncate with txn environments.
  364.         if os.path.isfile(file):
  365.             os.unlink(file)
  366.     else:
  367.         raise error, "flags should be one of 'r', 'w', 'c' or 'n'"
  368.     return flags | db.DB_THREAD
  369.  
  370. #----------------------------------------------------------------------
  371.  
  372.  
  373. # This is a silly little hack that allows apps to continue to use the
  374. # DB_THREAD flag even on systems without threads without freaking out
  375. # BerkeleyDB.
  376. #
  377. # This assumes that if Python was built with thread support then
  378. # BerkeleyDB was too.
  379.  
  380. try:
  381.     import thread
  382.     del thread
  383.     if db.version() < (3, 3, 0):
  384.         db.DB_THREAD = 0
  385. except ImportError:
  386.     db.DB_THREAD = 0
  387.  
  388.  
  389. #----------------------------------------------------------------------
  390.